/**
 *
 */
package edu.tjut.tjutcommunity.recommend.hotrecommend;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import edu.tjut.tjutcommunity.recommend.algorithms.RecommendAlgorithm;
import edu.tjut.tjutcommunity.recommend.algorithms.RecommendKit;
import edu.tjut.tjutcommunity.entity.Postlogs;
import edu.tjut.tjutcommunity.entity.Recommendations;
import edu.tjut.tjutcommunity.mapper.PostlogsMapper;
import edu.tjut.tjutcommunity.mapper.RecommendationsMapper;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import java.sql.Timestamp;
import java.util.*;

/**
 * @author tjut
 * @email
 * @github
 * @date 基于“热点新闻”生成的推荐，一般用于在CF和CB算法推荐结果数较少时进行数目的补充
 */
@Component
public class HotRecommender implements RecommendAlgorithm {

    public static final Logger logger = Logger.getLogger(HotRecommender.class);

    // 热点帖子的有效时间
    public static int beforeDays = -10;
    // 推荐系统每日为每位用户生成的推荐结果的总数，当CF与CB算法生成的推荐结果数不足此数时，由该算法补充
    public static int TOTAL_REC_NUM = 20;
    // 将每天生成的“热点帖子”ID，按照帖子的热点程度从高到低放入此List
    private static ArrayList<Integer> topHotNewsList = new ArrayList<Integer>();

    @Autowired
    RecommendationsMapper recommendationsMapper;

    @Autowired
    PostlogsMapper postlogsMapper;

    @Override
    public void recommend(List<Integer> users) {
        System.out.println("HR start at " + new Date());
        //重新生成当日热点新闻
        //formTodayTopHotNewsList();
        int count = 0;
        Timestamp timestamp = getCertainTimestamp(0, 0, 0);
        for (Integer userId : users) {
            try {
                //获得已经预备为当前用户推荐的新闻，若数目不足达不到单次的最低推荐数目要求，则用热点新闻补充
                QueryWrapper<Recommendations> qw = new QueryWrapper<>();
                qw.eq("uid",userId);
                qw.eq("has_recommend",0);
                qw.gt("create_time",timestamp);

                qw.groupBy("uid");
                List<Recommendations> recommendations = recommendationsMapper.selectList(qw);

                boolean flag = (recommendations != null);
                int tmpRecNums = 0;
                if (recommendations != null) {
                    tmpRecNums = recommendations.size();
                }
                int delta = flag ? TOTAL_REC_NUM - tmpRecNums : TOTAL_REC_NUM;
                Set<Integer> toBeRecommended = new HashSet<Integer>();
                if (delta > 0) {
                    int i = Math.min(topHotNewsList.size(), delta);
                    while (i-- > 0)
                        toBeRecommended.add(topHotNewsList.get(i));
                }
                RecommendKit.filterBrowsedPosts(toBeRecommended, userId);
                RecommendKit.filterReccedPosts(toBeRecommended, userId);
                RecommendKit.insertRecommend(userId, toBeRecommended.iterator(), RecommendAlgorithm.HR);
                count += toBeRecommended.size();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("HR has contributed " + (users.size() == 0 ? 0 : count / users.size()) + " recommending news on average");
        System.out.println("HR end at " + new Date());

    }

    public synchronized void formTodayTopHotNewsList() {
        topHotNewsList.clear();
        ArrayList<Integer> hotPostTobeReccommended = new ArrayList<Integer>();
        try {

            String days = RecommendKit.getInRecDate(beforeDays);
            QueryWrapper<Postlogs> qw = new QueryWrapper<>();
            qw.select("pid","count(*) as visitNums");
            qw.gt("create_time",days);
            qw.groupBy("pid");
            qw.orderByDesc("visitNums");
            List<Postlogs> postslogsList =  postlogsMapper.selectList(qw);
            if(postslogsList.isEmpty()) return;
            for (Postlogs postslog : postslogsList) {
                hotPostTobeReccommended.add(postslog.getPid());
            }
            topHotNewsList.addAll(hotPostTobeReccommended);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static List<Integer> getTopHotNewsList() {
        return topHotNewsList;
    }

    public static int getTopHopNewsListSize() {
        return topHotNewsList.size();
    }

    private Timestamp getCertainTimestamp(int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance(); // 得到日历
        calendar.set(Calendar.HOUR_OF_DAY, hour); // 设置为前beforeNum天
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        return new Timestamp(calendar.getTime().getTime());
    }
}
